package com.game.controller;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Random;

import com.game.connection.client.ClientMultiplayer;
import com.game.entity.Asteroid;
import com.game.entity.Bullet;
import com.game.entity.Ship;
import com.game.listener.dispatcher.ShipDispatcher;
import com.game.listener.event.ShipEvent;
import com.game.util.Util;

public class CopyOfGame extends Canvas implements Runnable, KeyListener {

	private String messagemBuffer;

	private boolean reciveMessage;
	private ClientMultiplayer player;

	public CopyOfGame() {
		messagemBuffer = "";
		reciveMessage = false;
	}

	// Loop game
	Thread gameLoop;
	// Usar isso como buffer secundário
	BufferedImage backBuffer;
	// Desenha os objetos do backBuffer
	Graphics2D g2D;
	// desenhar os formatos das caixas
	boolean showBounds = false;
	// Cria um arrey de asteroids
	int ASTEROIDS = 20;
	Asteroid[] ast = new Asteroid[ASTEROIDS];
	// Cria o jogador
	Ship ship = new Ship();

	Ship ship2 = new Ship();
	// Cria a transformação identidade(0,0)
	AffineTransform identity = new AffineTransform();
	// Cria gerador randomico
	Random rand = new Random();
	public void init() {

		setSize(800, 600);
		// Criando buffer
		backBuffer = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
		g2D = backBuffer.createGraphics();

		// Definindo a nave
		ship.setX(320);
		ship.setY(240);

		ship2.setX(300);
		ship2.setY(240);


		// Criando os asteroids
		for (int n = 0; n < ASTEROIDS; n++) {
			ast[n] = new Asteroid();
			ast[n].setRotationVelocity(rand.nextInt(3) + 1);
			ast[n].setX((double) rand.nextInt(600) + 20);
			ast[n].setY((double) rand.nextInt(440) + 20);
			ast[n].setMoveAngle(rand.nextInt(360));
			double ang = ast[n].getMoveAngle() - 90;
			ast[n].setVelX(Util.calcAngleMoveX(ang));
			ast[n].setVelY(Util.calcAngleMoveY(ang));
		}

		//
		addKeyListener(this);
	}

	@Override
	public void update(Graphics g) {

		//
		g2D.setTransform(identity);
		// apaga backgroud
		g2D.setPaint(Color.BLACK);
		g2D.fillRect(0, 0, getSize().width, getSize().height);

		// exibe algumas informações de estatus
		g2D.setColor(Color.WHITE);
		g2D.drawString("Nave :" + Math.round(ship.getX()) + ","+ Math.round(ship.getX()), 5, 10);
		g2D.drawString("Move Angle :" + Math.round(ship.getMoveAngle() + 90),5, 22);
		g2D.drawString("Face Angle :" + Math.round(ship.getFaceAngel()), 5, 34);
		if (reciveMessage) {
			g2D.drawString("Mensagem :" + Util.removeSpecialChar(messagemBuffer), 5, 46);
		}

		int ref = 46;
		for(String val : ship2.getMessage()){
			ref+=10;
			g2D.drawString("ship:"+ship2.getId()+"::"+val , 5,ref);
		}
		
		// Desenha grafico do jogo
		drawShip(ship);
		drawShip(ship2);
		drawBullets(ship);
		drawBullets(ship2);
		drawAsteroids();
		// Atualiza a tela
		paint(g);

	}

	private void drawAsteroids() {
		for (int n = 0; n < ASTEROIDS; n++) {
			if (ast[n].isAlive()) {
				g2D.setTransform(identity);
				g2D.translate(ast[n].getX(), ast[n].getY());
				g2D.rotate(Math.toRadians(ast[n].getMoveAngle()));
				g2D.setColor(Color.DARK_GRAY);
				g2D.fill(ast[n].getShape());
			}

		}

	}

	private void drawBullets(Ship ship) {
//		for (int n = 0; n < BULLETS; n++) {
		for(Bullet bullet: ship.getBullets()){
			// A bala esta sendo usada ?
			if (bullet.isAlive()) {
				g2D.setTransform(identity);
				g2D.translate(bullet.getX(), bullet.getY());
				g2D.setColor(Color.BLUE);
				g2D.draw(bullet.getShape());
			}
		}

	}

	private void drawShip(Ship ship) {
		g2D.setTransform(identity);
		g2D.translate(ship.getX(), ship.getY());
		g2D.rotate(Math.toRadians(ship.getFaceAngel()));
		g2D.setColor(Color.ORANGE);
		g2D.fill(ship.getShape());
		g2D.setColor(Color.red);

	}

	@Override
	public void paint(Graphics g) {
		g.drawImage(backBuffer, 0, 0, this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyPressed(KeyEvent k) {

		int keyCode = k.getKeyCode();

		if (!reciveMessage) {
			if ((keyCode == 77 || keyCode == 16)) {
				reciveMessage = true;
			}
			if (keyCode == KeyEvent.VK_LEFT || keyCode == 37) {
				ship.moveShipToLeft();
			}
			if (keyCode == KeyEvent.VK_RIGHT || keyCode == 39) {
				ship.moveShipToRight();
			}
			if (keyCode == KeyEvent.VK_UP || keyCode == 38) {
				ship.moveShipToUp();
			}
			if (keyCode == KeyEvent.VK_DOWN || keyCode == 40) {
				ship.moveShipToDown();
			}
			if ((keyCode == KeyEvent.VK_SPACE) || (keyCode == 32)
					|| (keyCode == KeyEvent.VK_ENTER)
					|| (keyCode == KeyEvent.VK_CONTROL) || (keyCode == 17)) {
				ship.fireEvent();
			}
		} else {
			messagemBuffer += k.getKeyText(keyCode).toUpperCase();
			if (keyCode == KeyEvent.VK_ENTER) {
				if (messagemBuffer.toUpperCase().indexOf("RESET") > -1) {
					resetShip();
				}
				if (!messagemBuffer.isEmpty()){
					ship.getMessage().add(Util.removeSpecialChar(messagemBuffer));
				}
				messagemBuffer = "";
				reciveMessage = false;
			}
		}
		ShipEvent event = new ShipEvent(ship.getX(), ship.getY(),ship.getFaceAngel());
		ShipDispatcher.getInstance().dispatchShipEvent(event);
	}

	
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		Thread t = Thread.currentThread();

//		this.player = new ClientMultiplayer("localhost", 4555, ship, ship2);

		Thread playerThread = new Thread(player);
		playerThread.start();
		while (t == gameLoop) {
			try {
				gameUpdate();
				// target framerate is 50 fps
				Thread.sleep(40);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			repaint();
		}
	}

	public void stop() {
		// kill the gameloop thread
		gameLoop = null;

	}

	private void gameUpdate() {
		updateShip(ship);
		updateShip(ship2);
		updateBullets(ship);
		updateBullets(ship2);
		updateAsteroids();
		checkcollisions();
	}

	private void resetShip() {
		ship.setX(320);
		ship.setY(240);
		ship.setFaceAngel(0);
		ship.setVelX(0);
		ship.setVelY(0);

		ShipEvent event = new ShipEvent(ship.getX(), ship.getY(),
				ship.getFaceAngel());
		ShipDispatcher.getInstance().dispatchShipEvent(event);
	}

	private void checkcollisions() {
		// iterate througth the asteroids array
		for (int m = 0; m < ASTEROIDS; m++) {
			// is this asteroid being used ?
			if (ast[m].isAlive()) {
				// check for colliison with bullet
				for(Bullet bullet: ship.getBullets()){
//				for (int n = 0; n < BULLETS; n++) {
					// is this bullets being used?
					if (bullet.isAlive()) {
						// perform the collision test

						if (ast[m].getBounds().contains(bullet.getX(),
								bullet.getY())) {
							bullet.setAlive(false);
							ast[m].setAlive(false);
							continue;
						}
					}
				}
				// check for collision with ship
				if (ast[m].getBounds().intersects(ship.getBounds())) {
					ast[m].setAlive(false);
					resetShip();
					continue;
				}
			}

		}
	}

	private void updateAsteroids() {
		// move and rotate the asteroids
		for (int n = 0; n < ASTEROIDS; n++) {
			Asteroid asteroid = ast[n];
			// is this asteroid being used?
			if (asteroid.isAlive()) {
				// update the asteroid X value
				asteroid.incX(asteroid.getVelX());

				// wrap the asteroid at screen edges
				if (asteroid.getX() < -20)
					asteroid.setX(getSize().width + 20);
				else if (asteroid.getX() > getSize().width + 20) {
					asteroid.setX(-20);
				}

				// update the asteroid Y value
				asteroid.incY(asteroid.getVelY());

				// wrap the asteroid at screen edges
				if (asteroid.getY() < -20)
					asteroid.setX(getSize().height + 20);
				else if (asteroid.getX() > getSize().height + 20) {
					asteroid.setY(-20);
				}

				// update the asteroid rotation
				asteroid.incMoveAngle(asteroid.getRotationVelocity());

				// Keep the angle within 0-359 degrees
				if (asteroid.getMoveAngle() < 0) {
					asteroid.setMoveAngle(360 - asteroid.getRotationVelocity());
				} else if (asteroid.getMoveAngle() > 360) {
					asteroid.setMoveAngle(asteroid.getRotationVelocity());
				}

			}

		}

	}

	private void updateBullets(Ship ship) {
		ship.updateMoveBulletsEvent(getSize().width, getSize().height);
	}

	private void updateShip(Ship ship) {
		ship.updateMoveShipEvent(getSize().width, getSize().height);
	}

	public void start() {
		gameLoop = new Thread(this);
		gameLoop.start();
	}

}
